package fem2.mesh_and_topology;

import math2.MathUtilities;

/**
 * Spatial criteria to check if a point lie in a surface
 * 
 * @author hbui
 * 
 */
public class LineSpatialCriteria extends SpatialCriteria {

	private double[] x0;
	private double[] v;
	private int c;

	/**
	 * line cross (x0, y0) with direction (u, v)
	 * 
	 * @param x0
	 * @param y0
	 * @param u
	 * @param v
	 */
	public LineSpatialCriteria(double x0, double y0, double u, double v) {
		if (Math.abs(u) > MathUtilities.tol6) {
			c = 0;
		} else if (Math.abs(v) > MathUtilities.tol6) {
			c = 1;
		} else {
			throw new Error("direction is vector zero. How come?");
		}
		this.x0 = new double[] { x0, y0 };
		this.v = new double[] { u, v };
	}

	/**
	 * line cross (x0, y0, z0) with direction (u, v, w)
	 * 
	 * @param x0
	 * @param y0
	 * @param z0
	 * @param u
	 * @param v
	 * @param w
	 */
	public LineSpatialCriteria(double x0, double y0, double z0, double u, double v, double w) {
		if (Math.abs(u) > MathUtilities.tol6) {
			c = 0;
		} else if (Math.abs(v) > MathUtilities.tol6) {
			c = 1;
		} else if (Math.abs(w) > MathUtilities.tol6) {
			c = 2;
		} else {
			throw new Error("direction is vector zero. How come?");
		}
		this.x0 = new double[] { x0, y0, z0 };
		this.v = new double[] { u, v, w };
	}

	@Override
	public boolean isSatisfied(double... x) {
		double t = (x[c] - x0[c]) / v[c];
		double norm = 0.0;
		for (int i = 0; i < x.length; i++) {
			norm += Math.pow(x[i] - (x0[i] + v[i] * t), 2);
		}
		return Math.sqrt(norm) < MathUtilities.tol6;
	}

	@Override
	public boolean isIntersected(double x0, double y0, double size) {
		assert this.x0.length == 2 : "not a 2d line";

		double a = -v[1];
		double b = v[0];
		double c = -(a * this.x0[0] + b * this.x0[1]);

		double d1 = a * x0 + b * y0 + c;
		double d2 = a * (x0 + size) + b * y0 + c;
		double d3 = a * (x0 + size) + b * (y0 + size) + c;
		double d4 = a * x0 + b * (y0 + size) + c;

		double dmin = Math.min(Math.min(d1, d2), Math.min(d3, d4));
		double dmax = Math.min(Math.max(d1, d2), Math.max(d3, d4));

		return dmin * dmax <= 0;
	}

	@Override
	public boolean isIntersected(double x0, double y0, double z0, double size) {
		assert this.x0.length == 3 : "not a 3d line";

		/*
		 * TODO: implement the collision detection of a line with a box. It's
		 * non-trivial.
		 */

		return super.isIntersected(x0, y0, z0, size);
	}

}
